package org.robot.scm.retry;

import cn.hutool.core.thread.ThreadUtil;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * 安全的简单重试机制，适用场景大部分为异系统接口间的调用
 *
 * @author awn
 */
@Slf4j
public class SimpleRetryable {

    private final AtomicInteger maxAttempts = new AtomicInteger(1);

    private final AtomicLong delayTime = new AtomicLong(0);

    public SimpleRetryable(int maxAttempts, long delayTime) {
        this.maxAttempts.set(maxAttempts);
        this.delayTime.set(delayTime);
    }

    public SimpleRetryable(int maxAttempts) {
        this.maxAttempts.set(maxAttempts);
    }

    @SneakyThrows
    public <T> T retry(SimpleFunction<T> function, Predicate<T> predicate) {
        AtomicReference<T> result = new AtomicReference<>();
        while (maxAttempts.decrementAndGet() >= 0) {
            ThreadUtil.safeSleep(delayTime.get());
            result.set(function.execute());
            if (predicate.test(result.get())) {
                return result.get();
            }
            log.warn("retry {}th times failed, continue", maxAttempts.get() + 1);
        }
        return result.get();
    }
}
